/*-------------------------------------------------------------------------
 - Copyright (c) 2024-2025 [XD-AMCC TEAM]
 - [XD-AMCC] is licensed under Mulan PSL v2.
 - You can use this software according to the terms and conditions of the Mulan PSL v2.
 - You may obtain a copy of Mulan PSL v2 at:
 -          http://license.coscl.org.cn/MulanPSL2
 - THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES
 - OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
 - TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 - See the Mulan PSL v2 for more details.
 ------------------------------------------------------------------------*/


/**
 * @brief API implementation of the class Parser.
 *
 * This parser is a Recursive-Descent-Parser:
 * (1) For each non-terminal X, there is a Recursive-Descent-Function(RDF)
 *     named RDF_X() which corresponds to the production of X.
 * (2) All RDF_X() are internal operations of this parser.
 *
 * In order to better understand the Recursive-Descent-Parsing,
 * this AMCC parser only performs syntax analysis and builds a parse tree.
 *
 * In this way, AMCC will perform other tasks in later pass(es), such as
 * symbol table construction, semantic calculations, and so on.
 *
 * @author  WXQ#XDU
 * @date    2024.11
 */

#include "inside/_parser_inner.h"

/** Initialize inner data of parser module */
int  parser_module_init() {
    // do nothing now
    return 0;
}

/** Clean inner data of parser module */
void parser_module_clean() {
    // do nothing now
}



t_parser_ptr parser_new(t_tokenstream_ptr pTokenStream) {
    t_parser_ptr pThis = (t_parser_ptr) calloc(1, sizeof(*pThis));
    if (NULL == pThis) {
        ERROR_REPORT_MALLOC();
        return NULL;
    }

    pThis->tokenStream = pTokenStream;
    log_debug("Parser %tx has created and initialized", pThis);
    return pThis;
}


void parser_destroy(t_parser_ptr pThis) {
    if (NULL == pThis)
        return;
    if (NULL != pThis->parseTree )
        tree_destroy ( pThis->parseTree );

    log_debug("Parser %tx has destroyed", pThis);
    free(pThis);
}


int parser_errors(t_parser_ptr pThis) {
    return (NULL == pThis) ? 0 : pThis->nErrors;
}


// Perform syntax analysis.
// Return Value:
//   0 on success, and return negative value on failure.
//  -1 on empty input;
//  -2 on any syntax error or memory allocation failures.
//
int parser_run(t_parser_ptr pThis) {
    if (NULL == pThis) {
        ERROR_REPORT_BUG("pass a NULL argument to parser_run()");
        return -2;
    }

    int  lastErrCounter = error_get_count();
    pThis->nErrors = 0;
    if ( tokenstream_isEmpty(pThis->tokenStream) ) {
        pThis->nErrors = 1 ;
        ERROR_REPORT_SYSTEM(EC_EMPTY_INPUT);
        return -1;
    }

    log_info(">>> %s(): Parser starts to work ...", __FUNCTION__ );
    log_info("*** NOTICE: This parser performs LL(*) analysis.");
    if ( amcc_is_logParerStack() && (LOG_DEBUG_ENABLE()) ) {
        log_info("*** NOTICE: Call stack for Recursive-Descent-Functions is coming...");
    } else {
        log_info("*** NOTICE: Call stack for Recursive-Descent-Functions is ONLY available");
        log_info("            if the log-level is DEBUG or TRACE");
        log_info("       AND  enable log call-stack of RDF functions.");
    }


    // Prefetch: get the reference to first token
    pThis->pNextToken = NEXT_TOKEN_K(pThis, 1);

    // Call the Recursive-Descent-Function of the Start-Symbol of grammar,
    // and get a pointer to the parse tree for whole input program
    pThis->maxCallDepth = 1;
    pThis->parseTree    = RDF_translationUnit (pThis);
    pThis->pNextToken   = NULL;
    pThis->nErrors      = error_get_count() - lastErrCounter;

    int retValue = 0;
    if ( NULL == pThis->parseTree ) {
        log_info("  %s(): RDF_translationUnit() returns null tree",
                 __FUNCTION__);
        retValue = -2;
    }
    else if ( pThis->nErrors > 0 ) {
        log_info("  %s(): RDF_translationUnit() returns an incomplete tree"
                 ", destroy it",
                 __FUNCTION__);
        tree_destroy ( pThis->parseTree );
        pThis->parseTree  = NULL;
        retValue = -2;
    }

    log_info("<<< %s(): Parser finished, found %d syntax errors, max-call-depth is %d",
             __FUNCTION__,  pThis->nErrors, pThis->maxCallDepth);
    return retValue;
}


t_tree_ptr parser_get_tree(t_parser_ptr pThis) {
    if (NULL == pThis) return NULL;
    return pThis->parseTree;
}


t_tree_ptr parser_GRAB_tree(t_parser_ptr pThis) {
    if (NULL == pThis)
        return NULL;

    t_tree_ptr treePtr = pThis->parseTree;
    pThis->parseTree = NULL;  // release the ownership
    if ( NULL != treePtr ) {
        log_info("NOTICE: CALLER MUST DESTROY the parse tree - "
                 "Caller of parser has grabbed it");
    }
    return treePtr;
}
